#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <i86.h>
#include <string.h>
#include <strings.h>

#include "BaseType.h"
#include "pcitypes.h"
#include "pci.h"
#include "list.h"
#include "TraceLog.h"
#include "util.h"
#include "tc1x.h"
#include "main.h"

#define MAX_DEV_NUM 1
USHORT AhciDevID[ MAX_DEV_NUM ][ 2 ] = {
    //{ 0x1106, 0x3514 }, // for VIA 514
    { 0x10EE, 0x0007 }  // for Xilinx PCIe Board
};

#define INVALID_OPT_CODE 0xFF
void usage(char** argv)
{
    printf("PCIe Data Acquisition Test Usage\n");
    printf("-----------------------------------------\n");
    printf("%s  [testcase num] [opt]\n", argv[ 0 ] );
    printf("\n");
    printf("testcase num : The number of test case to run simultaneously\n");
    printf("               Default value: do nothing but show this usage\n");
    printf("\n");

}
#if 0
UCHAR ParseOpt( int argc, char** argv )
{
    ULONG ret;
    if ( argc == 1 )
    {
        usage( argv );
        return INVALID_OPT_CODE;
    }
    if ( argc == 2 )
    {
        ret = atol( argv[ 1 ] );
        if ( ( ret < 1 ) || ( ret > 10 ) )
        {
            return INVALID_OPT_CODE;
        }
        else
        {
            return ret;
        }
    }
    if ( argc == 5 )
    {
        ret = atol( argv[ 1 ] );
        if ( ret > SUB_DISK_C )
        {
            printf("invalid option: disk %s\n", argv[ 1 ] );
            return INVALID_OPT_CODE;
        }
        else
        {
            gDiskIndex = ret;
        }
        ret = atol( argv[ 2 ] );
        if ( ret > 32 )
        {
            printf("invalid option: cmdnum %s\n", argv[ 2 ] );
            return INVALID_OPT_CODE;
        }
        else
        {
            gCmdNum = ret;
        }
        gLoopNum = atol( argv[ 3 ] );
        ret = atol( argv[ 4 ] );
        if ( ( ( gDiskIndex != SUB_DISK_A ) && ( ret > 128 ) )
            || ( gDiskIndex == SUB_DISK_A ) && ( ret > ( 24 * 1024 ) ) )
        {
            printf("invalid option: length %s\n", argv[ 4 ] );
            return INVALID_OPT_CODE;
        }
        else
        {
            gLength = ret;
        }
        return 0;
    }
    return INVALID_OPT_CODE;
}
#endif
STATUS FindAHCIDevice( PPCI_DEV_INFO PciDevInfo )
{
    WORD marker = 0;
    if ( pci_true == PciSearchForDevice( PciDevInfo->VendorID,
            PciDevInfo->DeviceID,
            &PciDevInfo->BusNum,
            &PciDevInfo->DevNum,
            &PciDevInfo->FuncNum,
            &marker ) 
        )
    {
        return SUCCESS;
    }else{
        return UNSUCCESSFUL;
    }
}
void main(int argc, char**argv)
{
    ULONG i;
    STATUS ret;
    AHCI_EXT ahciExt;

    PCI_DEV_INFO pciDevInfo;

    memset( (PVOID)&ahciExt, 0, sizeof( AHCI_EXT ) );
    ret = LogOpen( LOG_FILE_NAME );
    if ( SUCCESS != ret )
    {
        printf("Failed to open log file!\n");
        return;
    }
    ret = UNSUCCESSFUL;
    for( i = 0; i < MAX_DEV_NUM; i++)
    {
        ahciExt.PciDevInfo.VendorID = AhciDevID[ i ][ 0 ];
        ahciExt.PciDevInfo.DeviceID = AhciDevID[ i ][ 1 ];
        ret = FindAHCIDevice( &ahciExt.PciDevInfo );
        if ( ret == SUCCESS )
        {
            break;
        }
    }
    if ( ret == UNSUCCESSFUL )
    {
        LogMsg( COMP_INIT, DBG_NORMAL, "There isn't any Xilinx PCIe device!\n");
        LogMsg( COMP_INIT, DBG_NORMAL, "Expected Vendor ID/Device ID number: %d\n", MAX_DEV_NUM );
        for( i = 0; i < MAX_DEV_NUM; i++)
        {
        LogMsg( COMP_INIT, DBG_NORMAL, "[%2d]  0x%04X / 0x%04X\n", i, AhciDevID[ i ][ 0 ], AhciDevID[ i ][ 1 ] );
        }
        goto error_exit;
    }
    ret = SwInit( &ahciExt );
    if ( SUCCESS != ret )
    {
        LogMsg( COMP_INIT, DBG_NORMAL, "Failed to SwInit %s\n", StatusToString( ret ) );
        goto error_exit;
    }
    ret = TestCase1xEntry( &ahciExt );
    if ( SUCCESS != ret )
    {
        LogMsg( COMP_INIT, DBG_NORMAL, "Failed to TestCase1x %s!\n", StatusToString( ret ) );
    }
    LogMsg( COMP_INIT, DBG_NORMAL, "Test Completed!\n", StatusToString( ret ) );
    SwTermiate( &ahciExt);
error_exit:
    LogClose();
    return;
}




STATUS SwInit( PAHCI_EXT AhciExt )
{
        ULONG nBar0;
        ULONG mmioAddr;
        int i;
        ASSERT( AhciExt != NULL );
        mmioAddr = 0x10;
        nBar0 = PciReadConfigDWord( AhciExt->PciDevInfo.BusNum, AhciExt->PciDevInfo.DevNum, AhciExt->PciDevInfo.FuncNum, mmioAddr );
        if ( ( nBar0 & 0x1 ) == 1 )
        {
                LogMsg( COMP_INIT, DBG_ERROR, "PCI MMI/O %02X: %08X isn't memory method!\n", mmioAddr, nBar0);
                return UNSUCCESSFUL;
        }
        AhciExt->HBARegBaseAddress = DpmiMapPhysMemory( nBar0, 0x1000 );
        if ( AhciExt->HBARegBaseAddress == NULL )
        {
                LogMsg( COMP_INIT, DBG_ERROR, "Failed to DpmiMapPhysicalMemory for CapabilityRegister!\n");
                return UNSUCCESSFUL;
        }
        AhciExt->CmdRegAddr     = (ULONG*)( AhciExt->HBARegBaseAddress + 0x0 );
        AhciExt->XferLenRegAddr = (ULONG*)( AhciExt->HBARegBaseAddress + 0x4 );
        for( i = 0; i < PC_MEM_NUM; i++)
        {
                AhciExt->PcMemArray[ i ] = (ULONG*)( AhciExt->HBARegBaseAddress + 0x40 + i * 8 );
        }
        LogMsg( COMP_INIT, DBG_NORMAL, "Cmd  : %08X\n", AhciExt->CmdRegAddr     );
        LogMsg( COMP_INIT, DBG_NORMAL, "Xfer : %08X\n", AhciExt->XferLenRegAddr );
        for( i = 0; i < PC_MEM_NUM; i++)
        {
                LogMsg( COMP_INIT, DBG_NORMAL, "Mem%d : %08X\n", i, AhciExt->PcMemArray[ i ]           );
        }

        return SUCCESS;

}
STATUS SwTermiate( PAHCI_EXT AhciExt )
{
        int i;
    if ( AhciExt->HBARegBaseAddress )
    {
        DpmiUnMapPhysMemory( (ULONG)AhciExt->HBARegBaseAddress );
        AhciExt->HBARegBaseAddress = NULL;
    }
    AhciExt->CmdRegAddr     = NULL;
    AhciExt->XferLenRegAddr = NULL;
    for( i = 0; i < PC_MEM_NUM; i++)
    {
        AhciExt->PcMemArray[ i ] = NULL;
    }
    return SUCCESS;
}





